# Copyright (c) 2018 Presto Labs Pte. Ltd.
# Author: xguo

import json

from coin.exchange.okex.kr_rest.native_private_client import OkexOrderBase
from coin.exchange.okex_futures.kr_rest.futures_constants import (contract_type_list)


class OkexFuturesNativePrivateClient(OkexOrderBase):
  _valid_contract_type = contract_type_list
  _valid_status = {'unfilled': 1, 'filled': 2, None: None}

  def __init__(self, key_file, timeout=10):
    super().__init__(key_file, timeout=timeout)

  @classmethod
  def check_contract_type(cls, contract_type):
    assert contract_type in cls._valid_contract_type, \
        'Invalid contract type!'

  @classmethod
  def check_status(cls, status):
    assert status in cls._valid_status.keys(), 'Invalid status.'

  # Get OKEX Contract Account Info (Cross-Margin Mode)
  def query_POST_futures_userinfo(self):
    url = "future_userinfo.do"
    update = self._query(url, 'POST')
    return update

  # Get User Contract Positions (Cross-Margin Mode)
  def query_POST_futures_position(self, symbol, contract_type):
    self.check_contract_type(contract_type)
    url = "future_position.do"
    params = {
        'symbol': symbol,
        'contract_type': contract_type,
    }
    update = self._query(url, 'POST', params)
    return update

  # Place Orders.
  def query_POST_futures_trade(self,
                               symbol,
                               contract_type,
                               price,
                               amount,
                               trade_type,
                               lever_rate=10):
    self.check_contract_type(contract_type)
    assert lever_rate in (10, 20), 'Invalid leverage rate! %s' % lever_rate

    # trade_type
    # 1: open long position
    # 2: open short position
    # 3: liquidate long position
    # 4: liquidate short position
    assert trade_type in (1, 2, 3, 4), 'Invalid trade type'

    url = "future_trade.do"

    params = {
        'symbol': symbol,
        'contract_type': contract_type,
        'price': price,
        'amount': amount,
        'type': trade_type,
        'match_price': 0,  # 1 -> market order, which we do not use.
        'lever_rate': lever_rate,
    }

    update = self._query(url, 'POST', params)
    return update

  # Get Okex Contract Trade History (Not for Personal)
  def query_POST_futures_trades_histroy(self):
    # url = "future_trades_history.do"
    raise NotImplementedError()

  # Batch Trade
  def query_POST_batch_trade(self, symbol, contract_type, order_data, lever_rate=20):
    self.check_contract_type(contract_type)
    assert lever_rate in (10, 20), 'Invalid leverage rate! %s' % lever_rate
    url = "future_batch_trade.do"

    assert isinstance(order_data, list) and len(order_data) <= 5
    # TODO(xguo):

    params = {
        'symbol': symbol,
        'contract_type': contract_type,
        'order_data': json.dumps(order_data),
        'lever_rate': lever_rate,
    }

    update = self._query(url, 'POST', params)
    return update

  # Cancel Orders
  def query_POST_futures_cancel(self, symbol, contract_type, order_id):
    url = "future_cancel.do"
    params = {
        'symbol': symbol,
        'contract_type': contract_type,
        'order_id': order_id,
    }

    update = self._query(url, 'POST', params)
    return update

  # Get Order Info
  def query_POST_futures_order_info(self,
                                    symbol,
                                    contract_type,
                                    status=None,
                                    order_id=None,
                                    current_page=0,
                                    page_length=50):
    self.check_contract_type(contract_type)
    assert 0 < page_length <= 50, 'Page length should be in the range [1, 50]'
    assert current_page >= 0

    self.check_status(status)
    if order_id is None:
      assert status is not None
      order_id = -1
    else:
      assert status is None, 'If order_id is specified, do not specify status'

    url = "future_order_info.do"
    order_id = order_id or -1
    params = {
        "symbol": symbol,
        "contract_type": contract_type,
        "status": self._valid_status[status],
        "order_id": order_id,
        "current_page": current_page,
        "page_length": page_length,
    }
    update = self._query(url, "POST", params)
    return update

  # Get order information in batch mode.
  def query_POST_futures_orders_info(self, symbol, contract_type, order_id_list):
    self.check_contract_type(contract_type)
    assert type(order_id_list) in (list, tuple)
    url = "future_orders_info.do"
    params = {
        "symbol": symbol,
        "contract_type": contract_type,
        "order_id": ','.join(order_id_list),
    }
    update = self._query(url, 'POST', params)
    return update

  # Get User Account Info (Fixed-Margin Mode)
  def query_POST_futures_userinfo_4fix(self):
    url = "future_userinfo_4fix.do"
    update = self._query(url, 'POST')
    return update

  # Get User Positions (Fixed-Margin Mode)
  def query_POST_futures_position_4fix(self, symbol, contract_type):
    url = "future_position_4fix.do"
    self.check_contract_type(contract_type)
    params = {
        'symbol': symbol,
        'contract_type': contract_type,
    }
    update = self._query(url, 'POST', params)
    return update

  # Get Forced Liquidation Orders
  def query_POST_futures_explosive(self):
    # url = "future_explosive.do"
    raise NotImplementedError()

  # Account Fund Transfer
  def query_POST_futures_devolve(self):
    # url = "future_devolve.do"
    raise NotImplementedError()
